---
title: '初探 HarmonyOS'
date: '2024-04-11 22:10:43'
images: ['https://pic.rmb.bdstatic.com/bjh/cms/231228/1db92d05c5390c8f66efc3d8be0f2845_1703765840.8801_900.jpeg@h_1280']
summary: 'HarmonyOS 是华为推出的一款面向全场景的分布式操作系统，它支持多种设备，包括智能手机、平板电脑、智能手表等。HarmonyOS 提供了丰富的 API 和工具，可以帮助开发者构建跨设备的分布式应用。'
tags: 
 - APP
---

## HarmonyOS

HarmonyOS Next 开发语言是 ArkTS，类似于TypeScript，对于学习过前端开发人员来说，上手难度较低。
项目结构有点像 Java 、Kotlin ，但是 ArkTS 是基于 TypeScript 的，所以 TypeScript 的语法都可以使用。


### DevEco Studio 安装

[DevEco Studio官网](https://developer.huawei.com/consumer/cn/download/)




## 项目开发

页面的开发和前端的移动端开发很像，在单位使用尽量使用vp而不是px，使各个设备都适配UI
px转vp的方式为：vp2px(100) 表示 100px转vp

``` arkts
@Entry
@Component
struct Index {
  @State message: string = 'HarmonyOS';
  @State search: string = '请输入搜索内容';

  build() {
    RelativeContainer() {
      Stack({alignContent:Alignment.Bottom}){
        // 顶部搜索
        Stack({alignContent:Alignment.Top}){
          Row(){
            TextInput({
              placeholder:this.search
            })
              .onFocus(()=>{
                console.log('onFocus')
              })
          }
          .height(80)
          .width('100%')
          .backgroundColor("blue")
        }
        .zIndex(1)
        .position({
          top:0,
          left:0
        })
        // 滚动区域
        Scroll(){
          Column(){
            Row(){
              Text(this.message)
                .id('HelloWorld')
                .fontSize($r('app.float.page_text_font_size'))
                .fontWeight(FontWeight.Bold)
                .alignRules({
                  center: { anchor: '__container__', align: VerticalAlign.Center },
                  middle: { anchor: '__container__', align: HorizontalAlign.Center }
                })
                .onClick(() => {
                  this.message = this.message== 'Welcome'?'HarmonyOS':'Welcome';
                })
            }
            .height('100%')

            Row(){
              Text('滚动内容1').height(500)
            }
            Row(){
              Text('滚动内容2').height(500)
            }
          }

        }
        // 底部 tab
        Row(){
          Text('tab1')
            .textAlign(TextAlign.Center)
            .layoutWeight(1)
            .fontWeight(FontWeight.Bold)
          Text('tab2')
            .layoutWeight(1)
            .textAlign(TextAlign.Center)
          Text('tab3')
            .layoutWeight(1)
            .textAlign(TextAlign.Center)
          Text('tab4')
            .layoutWeight(1)
            .textAlign(TextAlign.Center)
            .onClick(()=>{
              console.log('点击了tab4')
            })
        }
        .width('100%')
        .height(70)
        .position({
          bottom:0,
          left:0
        })
      }
    }
    .height('100%')
    .width('100%')
  }
}
```
![页面展示](https://kodo.huixiangwuyou.com/blog/images/app/2250523233804.png)

### 页面组件
- Text：文本组件
- Image：图片组件
  - 网络路径：Image('https://baidu.com/images/1.png') 表示图片的路径
  - 本地路径：Image($('app.images.avatar')) 图片默认读取名称，不需要加后缀（不要设置相同名称的不同文件）
  - fillColor:填充颜色
- Button：按钮组件
- Scroll：滚动组件
- Stack：层叠组件
  - alignContent: Alignment.Center
- CheckBox：复选框组件
- Span：文本组件
- Column：列组件 不具备可滚动效果
- Row：行组件 不具备可滚动效果
- Divider：分割线组件
- AlertDialog：弹窗组件
- Navigator：导航组件
- Tab：标签组件
- List：列表组件
- Card：卡片组件
- Badge：角标组件
- Dialog：对话框组件
- Toast：提示框组件
- Loading：加载组件
- Grid：网格组件
- Picker：选择器组件
- DatePicker：日期选择器组件
- TimePicker：时间选择器组件
- Switch：开关组件
- Slider：滑块组件

####  Swiper- 轮播图组件
[文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper)

```arkts
@Entry
@Component
struct SwiperSample {
  build() {
   Column() {
    Swiper() {
      Image('https://baidu.com/images/1.png')
      Image('https://baidu.com/images/2.png')
      Image('https://baidu.com/images/3.png')
    }
    .indicator(true) // 显示指示器
    .indicatorSize(10) // 指示器大小
    .indicatorPosition(IndicatorPosition.Bottom) // 指示器位置
    .indicatorAlign(IndicatorAlign.Center) // 指示器对齐方式
    .indicatorShape(IndicatorShape.Rect) // 指示器形状
    .interval(3000)  // 轮播间隔时间
    .duration(500)
    .loop(true)  //开启循环
    .height(300)
    .autoplay(true)  // 自动播放
   }
  }
}
```

#### Scroll- 滚动组件
[文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-scroll)
```arkts

@Entry
@Component
struct Index {
 myScroll:Scroll = new Scroll()

 build() {
  // 滚动区域
  Scroll(this.myScroll){
    Column(){
      Row(){
        Text('滚动内容1').height(500)
      }
    }
  }
  .height(500)
  .scrollable(ScrollDirection.Horizontal) // 水平滚动  默认纵向
  .scrollBar(true) // 显示滚动条
  .scrollBarColor('#ff2787d9') // 滚动条颜色
  .scrollBarWidth(10) // 滚动条宽度
  .scrollBarHeight(10) // 滚动条高度
  .scrollBarRadius(5) // 滚动条圆角
  .onScroll((x,y)=>{
    // 可以监听滚动事件，设置回到顶部按钮的显示与隐藏
  })
 }
 .Button('按钮')
 .onClick(()=>{
   const y= this.myScroll.currentOffset().yOffset // 获取当前滚动位置
   this.myScroll.scrollEdge(100,0,0) // 滚动到指定位置
 })
}

```

#### Tabs- 组件
[文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-tabs)
```arkts

@Entry
@Component
struct Index {
 titles:string[]=['首页'，'关注'，"热门'，"财经"，'美食'，'旅行']
 private controller: TabsController = new TabsController();

 build() {
  Tabs({barPosition: BarPosition.Start, index: 1, controller: this.controller }){
   ForEach(this.titles,(item:string,index)=>{
    Tabcontent(){
      Text(`${item}内容`)
    }
    .tabBar(item)
   }
  }
  .vertical(true)
  .scrollable(true) // 
  .onChange((x,y)=>{
    // 切换事件，可以设置tabbar的样式
  })
 }
}
```
tabs属性
- barPosition :调整位置 开头 或 结尾 (参数)
- vertical:调整导航 水平 或 垂直
- scrollable:调整是否 手势滑动 切换
- animationDuration:点击滑动动画时间


### 页面属性设置

- layoutweight：类似css的弹性盒子的flex属性，设置权重，使页面元素可以自适应
- justifyContent：类似css的flex-start、flex-end、center、space-between、space-around，设置元素在主轴上的对齐方式
- margin：margin(\{top: 10, left: 10, right: 10, bottom: 10\}) 设置外边距
- alignItems: alignItems(\{VerticalAlign.Center\}) 设置元素在交叉轴上的对齐方式
- backgroundImage：backgroundImage('https://baidu.com/images/1.png') 设置背景图片
- backgroundImageSize：backgroundImageSize(\{ImageSize.Cover\}) 设置背景图片大小
- **Flex**:
  - direction：flexDirection(\{FlexDirection.Row\}) 设置主轴方向
  - justifyContent：FlexAlign.SpaceAround
  - alignItems：AlignItems.Center
- **Padding**:
- flexDirection：flexDirection(\{FlexDirection.Column\}) 设置主轴方向

#### 多态样式

```arkts
@Entry
@Component
struct StateStylesSample {
  build() {
    Column() {
      Button('Button1')
        .stateStyles({
          focused: {
            .backgroundColor('#ffffeef0')
          },
          pressed: {
            .backgroundColor('#ff707070')
          },
          normal: {
            .backgroundColor('#ff2787d9')
          }
        })
        .margin(20)
      Button('Button2')
        .stateStyles({
          focused: {
            .backgroundColor('#ffffeef0')
          },
          pressed: {
            .backgroundColor('#ff707070')
          },
          normal: {
            .backgroundColor('#ff2787d9')
          }
        })
    }.margin('30%')
  }
}
```


### 页面变量
页面变量分为三种：全局变量(文件组件外变量)、组件变量、组件状态变量
全局变量和组件变量在页面初始化的时候只渲染一次，组件状态变量在页面渲染的时候会根据状态值进行渲染

```arkts
// 全局变量
const globalVar = '全局变量'

@Entry
@Component
struct Index {
  // 组件变量
  const componentVar = '组件变量'

  // 组件状态变量
  @state componentStateVar = '组件状态变量'

  build() {}
}
```

> @state 的变量若是嵌套的太深是无法触发渲染的, 只有第一层属性赋值的变化，即Object.keys(observedObject)返回的属性才渲染

```arkts
@state p:person={
  name:'张三',
  age:18,
  attr:{
    height:180,
    weight:70
  }
}

// 只修改一个属性
p.attr.height = 120  // 不会触发渲染
// 直接修改了指针方向
p.attr={
  height:120,
  weight:70
} // 会触发渲染
```

#### 组件传值

![组件传值](https://kodo.huixiangwuyou.com/blog/images/app/2250524222427.png)

#### @Link
父子组件双向传值

```arkts
// 父组件
@Entry
@Component
struct Index {
  @State count: string = '父组件数据'
  build() {
    Column() {
      Text('父组件')
      ChildComponent(
       childData: this.count
      )
    }
  }
}

// 子组件
@Component
struct ChildComponent {
  @Link childData: string = ''
  build() {
    Column() {
      Text('子组件')
      Text(this.childData)
    }
  }
}
```

#### @Prvide|@Consume
父子组件单向传值

```arkts
// 父组件
@Entry
@Component
struct Index {
  @Provide provideData: number = 3
  build() {
    Column() {
      Text('父组件')
      ChildComponent()
    }
  }
}

// 子孙组件
@Component
struct ChildComponent {
  @Consume provideData: string = ''
  build() {
    Column() {
      Text('子组件')
      Text(this.provideData)
    }
  }
}
```

![@Observed & @ObjectLink](https://kodo.huixiangwuyou.com/blog/images/app/250524225832.png)

> ObjectLink 主要针对的是数组对象的更新，比如一个数组对象，当数组对象中的某个属性发生变化时，ObjectLink可以监听到这个变化，然后更新对象组件，但是不想更新整个对象组件，只想更新组件内关联的页面元素，这时候用ObjectLink就可以实现这个功能

### 页面装饰器

- @Entry：入口组件
- @Component：组件
- @Builder：构建函数
- @Extend：扩展组件
- @Styles：样式
- @Preview：预览组件
- @Prop:  父子组件属性传递
- @Link：父子组件双向传值
- @Provide：父组件向子组件传值
- @Consume：子组件向父组件传值
- @State：组件状态变量
- @ObjectLink：对象组件监听
- @Observed：监听对象组件

### 样式|结构重用

#### @Extend
扩展组件(样式、事件)
```arkts
<!-- 定义 -->
@Extend(Text)  // 继承组件类型：Text、Button、Image等
function TextFont(){
  .fontSize(20)
  .layoutWeight(1)
  .textAlign(TextAlign.Center)
}

<!-- 使用 -->
 Text('tab1')
   .TextFont()
   .fontWeight(FontWeight.Bold)
 Text('tab2')
   .TextFont()

<!-- 不仅支持样式，还支持在定义的继承传递参数渲染不同数据 -->
@Extend(Text)
function TextFont(index: number){
  .fontSize(20)
  .layoutWeight(1)
  .textAlign(TextAlign.Center)
  .onClick(()=>{
    console.log('点击了tab1'+index)
  })
}
```

#### @Styles
抽取通用属性、事件,定义的函数不可以传递参数

```arkts
<!-- 全局定义 -->
@Styles CommonStyle(){
  .fontSize(20)
  .layoutWeight(1)
  .textAlign(TextAlign.Center)
}

// 直接在UI组件链式调用即可

<!-- 组件定义 -->
@Styles UIStyle(){
  .fontSize(20)
  .onClick(()=>{
   // 访问组件内的变量
   console.log(this.message)
  })
}
```

#### @Builder
自定义构建函数(结构、样式、事件)
```arkts
<!-- 全局定义 -->

@Builder
function GlobalUI(msg:string){
  Row(){
    Text('tab1')
      .TextFont()
      .fontWeight(FontWeight.Bold)
    Text('tab2')
      .TextFont()
    Text('tab3')
      .TextFont()
    Text('tab4')
      .TextFont()
      .onClick(()=>{
        console.log(msg)
      })
  }
  .width('100%')
  .height(70)
  .position({
    bottom:0,
    left:0
  })
}

<!-- 使用 -->
GlobalUI('点击了tab4')

<!-- 在组件内定义 -->
@Entry
@Component
struct Index {
  @Builder
  GlobalUI(msg:string){
    // code
  }
  build() {
    RelativeContainer() {
      // 底部 tab
      GlobalUI('点击了tab4')
    }
    .height('100%')
    .backgroundColor(Color.Orange)
    .width('100%')
  }
}
```


#### @Component
自定义组件，可以直接将页面的部分内容直接封装成一个组件，在页面引入使用。也可以直接在页面内定义自定义组件，然后直接使用，不需要`export`或者`export default`导出

```arkts
// 组件文件夹文件定义 /components/GlobalUI.ets
@Component
export struct GlobalUI{
 // 定义组件变量和函数
 title:string //可以参数覆盖
 @state name:string='' //可以参数覆盖
 publicMethod = ()=>{} //可以参数覆盖
 sayHi(){} //不可以参数覆盖
 build(){
  Row(){
   
  }
 }
}

// 或者直接导出单个组件
export default GlobalUI

// 然后在页面引入使用
import {GlobalUI} from '../components/GlobalUI.ets'

@Entry
@Component
struct Index {
  build() {
    GlobalUI(

     publicMethod(){}
    )
  }
}
```
> 若是要预览自定义组件，需要在`@Component` 上添加 `@Preview`

> 组件插槽 @Builder、@BuilderParam 可以让自定义组件 允许外部传递 UI。

```arkts
@Component
export struct BuildUI{
 // 定义组件变量和函数
 title:string
 @BuilderParam ContentBuilder:()=>void=this.defaultContentBuilder //可以参数覆盖
 publicMethod = ()=>{}
 @Builder
 defaultContentBuilder(){
  Text('默认内容')
 } 
 
 build(){
  Row(){
   // 使用 @BuilderParam 装饰的成员变量
   this.ContentBuilder()
  }
 }
}

// 然后在页面引入使用
import {GlobalUI} from '../components/GlobalUI.ets'

@Entry
@Component
struct Index {
  build() {
    BuildUI(
     publicMethod(){}
    ){
     Text('插槽内容')
    }
  }
}
```
![多个插槽](https://kodo.huixiangwuyou.com/blog/images/app/20250524194510.png)

### 页面渲染

#### ForEach-渲染控制

对于重复的元素，可以使用ForEach进行渲染控制

```arkts
ForEach(this.list, (item,index) => {
 Row(){
   Text(item)
     .fontSize(20)
})

```

### 页面路由
[路由文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-set-navigation-routing)
创建路由页面的方式有两种：
- 直接在`pages`文件夹下创建页面arkts文件，或者在pages文件夹下创建文件夹，然后在文件夹下创建页面arkts文件，这种方式需要手动在路由中注册。即在`resources/base/proofile`文件夹下的`main_pages.json`文件中添加路由配置。
- 直接在`pages`文件夹下右键创建页面文件的时候选择`New=>Page`，或者在pages文件夹下创建文件夹，然后在文件夹下创建页面文件选择`New=>Page`，文件夹下创建的页面文件会自动在路由中注册。

```arkts
// Navigation(推荐)
@Entry
@Component
struct Index {
  // 创建一个页面栈对象并传入Navigation
  pageStack: NavPathStack = new NavPathStack();
  build() {
    Navigation(this.pageStack) {
     Text('首页').onClick(()=> {
        this.pageStack.pushPath({
          url: 'pages/second_page',
          params: {
            name: 'second_page'
          }
     })
    }
    .title('Main')
  }
}
// 普通跳转
this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" });
this.pageStack.pushPathByName("PageOne", "PageOne Param");
// 带返回回调的跳转，跳转时添加onPop回调，能在页面出栈时获取返回信息，并进行处理。
this.pageStack.pushPathByName('PageOne', "PageOne Param", (popInfo) => {
  console.log('Pop page name is: ' + popInfo.info.name + ', result: ' + JSON.stringify(popInfo.result));
});
// 带错误码的跳转，跳转结束会触发异步回调，返回错误码信息。
this.pageStack.pushDestination({name: "PageOne", param: "PageOne Param"})
  .catch((error: BusinessError) => {
    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
    console.info('Push destination succeed.');
  });
this.pageStack.pushDestinationByName("PageOne", "PageOne Param")
  .catch((error: BusinessError) => {
    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
    console.info('Push destination succeed.');
  });
// 删除栈中name为PageOne的所有页面
this.pageStack.removeByName("PageOne");
// 删除指定索引的页面
this.pageStack.removeByIndexes([1, 3, 5]);
// 删除指定id的页面
this.pageStack.removeByNavDestinationId("1");
// 移动栈中name为PageOne的页面到栈顶
this.pageStack.moveToTop("PageOne");
// 移动栈中索引为1的页面到栈顶
this.pageStack.moveIndexToTop(1);
// 获取栈中所有页面name集合
this.pageStack.getAllPathName();
// 获取索引为1的页面参数
this.pageStack.getParamByIndex(1);
// 获取PageOne页面的参数
this.pageStack.getParamByName("PageOne");
// 获取PageOne页面的索引集合
this.pageStack.getIndexByName("PageOne");

// router (不推荐)

// 导入 两种方式都可以
import router from@ohos .router';
import {router} from "@kit.ArkUI"

//1.调用方法-普通跳转(可以返回)
router.pushUrl({
 url:页面地址
})

//2.调用方法-替换跳转(无法返回)
router.replaceUrl({
 url:'页面地址
})

//3.调用方法-(返回)
router.back()

//获取页面栈长度
router.getLength()
// 清空页面栈
router.clear()

```
> 页面栈跳转最长 32 个页面记录

路由模式
- `standard`：标准模式，页面栈跳转，跳转的路由不管之前是否存在都在页面栈中添加
- `single`：单任务模式，跳转时，如果栈中存在目标页面，则将目标页面以上的页面全部出栈，并跳转到目标页面

```arkts
//1.调用方法-普通跳转(可以返回)
router.pushUrl({
 url:页面地址
 mode:'standard'
})

//2.调用方法-替换跳转(无法返回)
router.replaceUrl({
 url:'页面地址
 mode:'single'
})
```

#### 获取路由参数

- aboutToAppear：在创建自定义组件后，执行其build()函数之前执行（NavDestination创建之前），允许在该方法中改变状态变量，更改将在后续执行build()函数中生效。
- onWillAppear：NavDestination创建后，挂载到组件树之前执行，在该方法中更改状态变量会在当前帧显示生效。
- onAppear：通用生命周期事件，NavDestination组件挂载到组件树时执行。
- onWillShow：NavDestination组件布局显示之前执行，此时页面不可见（应用切换到前台不会触发）。
- onShown：NavDestination组件布局显示之后执行，此时页面已完成布局。
- onActive：NavDestination处于激活态（处于栈顶可操作，且上层无特殊组件遮挡）触发。
- onWillHide：NavDestination组件触发隐藏之前执行（应用切换到后台不会触发）。
- onInactive：NavDestination组件处于非激活态（处于非栈顶不可操作，或处于栈顶时上层有特殊组件遮挡）触发。
- onHidden：NavDestination组件触发隐藏后执行（非栈顶页面push进栈，栈顶页面pop出栈或应用切换到后台）。
- onWillDisappear：NavDestination组件即将销毁之前执行，如果有转场动画，会在动画前触发（栈顶页面pop出栈）。
- onDisappear：通用生命周期事件，NavDestination组件从组件树上卸载销毁时执行。
- aboutToDisappear：自定义组件析构销毁之前执行，不允许在该方法中改变状态变量。

```arkts
aboutToAppear():void{
 console.log('aboutToAppear:路由传递参数',this.pageStack.params)
}

onActive():void{
 console.log('onActive:路由传递参数',this.pageStack.params)
}

onShown():void{
 console.log('onShown:页面组件渲染完成')
}

onDisappear():void{
 console.log('onDisappear:页面销毁')
}
```
![页面生命周期](https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20250522111930.88555010362472723567920566261683:50001231000000:2800:8856C99770D2FA936F993419BF96D9B413273A797ACDA54D7FE587BC9FCD086E.png)

#### 路由拦截
在willShow回调中通过修改路由栈来实现路由拦截重定向的能力。
```arkts
this.pageStack.setInterception({
  willShow: (from: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar",
    operation: NavigationOperation, animated: boolean) => {
    if (typeof to === "string") {
      console.log("target page is navigation home page.");
      return;
    }
    // 将跳转到PageTwo的路由重定向到PageOne
    let target: NavDestinationContext = to as NavDestinationContext;
    if (target.pathInfo.name === 'PageTwo') {
      target.pathStack.pop();
      target.pathStack.pushPathByName('PageOne', null);
    }
  }
})
```

## 部署

### 项目解构

- entry:HarmonyOS工程模块，编译构建生成一个HAP包。
  - src>main>ets:用于存放ArkTS源码，
  - src>main>ets>entryability:应用/服务的入口，
  - src>main>ets>pages:应用/服务包含的页面。
  - src>main>resources:用于存放应用/服务所用到的资源文件。
  - src>main>module.json5:模块应用配置文件。
  - build-profile.json5:当前的模块信息、编译信息配置项，包括buildOption、targets配置等
  - hvigorfile.ts:模块级编译构建任务脚本，开发者可以自定义相关任务和代码实现。
  - obfuscation-rules.txt:混淆规则文件。。
- oh-modules:用于存放三方库依赖信息。
- build-profile.json5:应用级配置信息，包括签名signingConfigs、产品配置products等。。
- hvigorfile.ts:应用级编译构建任务脚本。

> [项目名称]/entry/src/main/ets/entryability/EntryAbility.ets

在当前文件内配置了应用的各种生命配置
- onCreate：应用创建时调用
- onDestroy：应用销毁时调用
- onWindowStageCreate：应用窗口创建时调用
  - 在windowStage.loadContent可以设置App默认启动页
- onWindowStageDestroy：应用窗口销毁时调用
- onForeground：应用进入前台时调用
- onBackground：应用进入后台时调用


#### AppScope/app.json5

```json
{
  "app": {
    // 包名 不可省略
    "bundleName": "com.example.myapplication", 
    //  应用开发厂商描述 不可省略
    "vendor": "example",
    //  应用版本号
    "versionCode": 1000000,
    //  应用版本名称
    "versionName": "1.0.0",
    //  应用图标
    "icon": "$media:layered_image",
    //  应用名称
    "label": "$string:app_name"
  }
}
```   

#### src/main/module.json5

[配置](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/module-configuration-file)

```json
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet",
      "2in1"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:layered_image", //应用图标
        "label": "$string:EntryAbility_label",//应用名称
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      }
    ],
    "extensionAbilities": [
      {
        "name": "EntryBackupAbility",
        "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
        "type": "backup",
        "exported": false,
        "metadata": [
          {
            "name": "ohos.extension.backup",
            "resource": "$profile:backup_config"
          }
        ],
      }
    ]
  }
}

```


### Ability

一个手机可以同时运行多个应用，每个应用可以包含多个Ability，每个Ability负责完成一个特定的功能。Ability是应用的基本组成单元，一个应用可以包含一个或多个Ability。支持应用内的交互（微信和微信小程序或者说是启动了微信和打开微信的任务（视频语音聊天、小程序））、应用间的交互、数据共享、远程服务调用等。
[更多介绍](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/abilitykit-overview)

#### 创建Ability

每个项目都可以由多个Ability组成，每个Ability都对应一个页面，每个页面都对应一个Ability。在module.json5中配置了Ability，可以设置APP默认启动的Ability。在ets中创建对应的Ability文件,可以设置启动的Ability的默认启动页。
例如：打开微信，可以打开微信的首页，也可以打开微信的某个内置小程序。

![创建Ability](https://kodo.huixiangwuyou.com/blog/images/app/20250525153451.png)

```json
{
  "module": {
    "name": "entry",
    ....
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      },
      {
        "name": "twoAbility",
        "srcEntry": "./ets/twoability/twoAbility.ets",
        "description": "$string:twoAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:twoAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background"
      }
    ],
    "extensionAbilities": []
  }
}
```
> 在上面的 abilities 属性可以设置应用启动的默认Ability（直接将exported和skills属性剪切到另一个对象即可）。icon、label、startWindowIcon、startWindowBackground属性可以设置应用启动页面的图标、名称、启动页面的图标、启动页面的背景色。


#### Ability的交互

Ability 同模块的交互（即打开内置小程序）

[示例](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/uiability-launch-type)

Ability 应用间交互（淘宝或者京东打开微信和支付宝支付）

[示例](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/link-between-apps-overview)


### webview

[webview相关](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkweb-api)


